一、概述

最近家里有点事,趁在家的这段时刻,温习一下C言语中心常识,后的底层开发、音视频开发、跨平台开发、算法等方向的进一步研究与学习埋下伏笔

本篇文章接着上一篇持续对C言语的中心语法常识进行温习

二、C 言语中心语法|结构体、共用体

1. 结构体

C 数组答应界说可存储相同类型数据项的变量,结构是 C 编程中另一种用户自界说的可用的数据类型,它答应存储不同类型的数据项

结构用于表明一条记录,假设您想要跟踪图书馆中书本的动态,您或许需求跟踪每本书的下列属性:

  • Title
  • Author
  • Subject
  • Book ID

界说结构

为了界说结构,您有必要运用 struct 句子。struct 句子界说了一个包括多个成员的新的数据类型,struct 句子的格局如下:

struct name{
  member-list;
  member-list;
  ...
}name_tag; 

name 是结构的标签。

member-list 是规范的变量界说,比方 int i;或许 float f,或许其它有用的变量界说。

name_tag 结构变量,界说在结构的结尾,最终一个分号之前,你能够指定一个或多个结构变量,下面是声明 Book 的结构办法:

struct Books{
  char title[50];
  char author[50];
  char subject[100];
  int book_id;
} book;

留意:在界说结构体的时分name、member-list、name_tag 这 3 部分至少要呈现 2 个。

结构体变量的初始化

和其它类型变量一样,在初始化的时分能够指定初始值。

//
//  main.c
//  08-结构体
//
//  Created by VanZhang on 2022/5/17.
//
#include <stdio.h>
//界说一个 Books 结构体,相似于 iOS 中的 类
struct  Books{
    char title[50];
    char author[50];
    char subject[100];
    int book_id;
    double rmb;
};
void test1(void) {
    // insert code here...
  /*
   //界说 结构体,且初始化一个 该类型的结构体的临时变量
   struct  Books{
       char title[50];
       char author[50];
       char subject[100];
       int book_id;
       double rmb;
   }  book = {"ObjC", "iOS", "C 言语", 666, 55.5};
   */
    struct Books book = {"ObjC", "iOS", "C 言语", 666, 55.5};
    printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\nrmb: %f\n", book.title,
             book.author, book.subject, book.book_id, book.rmb);
}
int main(int argc, const char * argv[]) {
    test1();
    return 0;
}

输出:

title : ObjC
author: iOS
subject: C 言语
book_id: 666
rmb: 55.500000
Program ended with exit code: 0

拜访结构成员

 #include <string.h>
struct Books2 {
    char title[50];
    char author[50];
    char subject[100];
    int book_id;
};
void test2(void){
//    char tmp[50] = "abcd";
//    printf("tmp:%s\n",tmp);
      //拜访 Books2 结构成员
    struct Books2 Books2A;//声明 Books2A 类型为 Books2
    struct Books2 Books2B;//声明 Books2B 类型为、 Books2
//    Books2A.title[5] = "ABCD";//无法正确赋值?
    //Books2A 胪陈//能够正确赋值
    strcpy(Books2A.title, "C Plus");
    strcpy(Books2A.author, "LuckyVan");
    strcpy(Books2A.subject, "C");
    Books2A.book_id = 666888;
    //Books2B 胪陈
    strcpy(Books2B.title, "C++ Plus");
    strcpy(Books2B.author, "LuckyVan");
    strcpy(Books2B.subject, "C++");
    Books2B.book_id = 666999;
    // 输出 Book1 信息
    printf("Book 1 title : %s\n", Books2A.title);
    printf("Book 1 author : %s\n", Books2A.author);
    printf("Book 1 subject : %s\n", Books2A.subject);
    printf("Book 1 book_id : %d\n", Books2A.book_id);
    // 输出 Book2 信息
    printf("Book 2 title : %s\n", Books2B.title);
    printf("Book 2 author : %s\n", Books2B.author);
    printf("Book 2 subject : %s\n", Books2B.subject);
    printf("Book 2 book_id : %d\n", Books2B.book_id);
}
int main(int argc, const char * argv[]) {
//    test1();
    test2();
    return 0;
}

输出:

Book 1 title : C Plus
Book 1 author : LuckyVan
Book 1 subject : C
Book 1 book_id : 666888
Book 2 title : C++ Plus
Book 2 author : LuckyVan
Book 2 subject : C++
Book 2 book_id : 666999
Program ended with exit code: 0

结构作为函数参数

//函数声明
void printBook(struct Books2 books2);
void test3(void){
//    char tmp[50] = "abcd";
//    printf("tmp:%s\n",tmp);
      //拜访 Books2 结构成员
    struct Books2 Books2A;//声明 Books2A 类型为 Books2
    struct Books2 Books2B;//声明 Books2B 类型为、 Books2
//    Books2A.title[5] = "ABCD";//无法正确赋值?
    //Books2A 胪陈//能够正确赋值
    strcpy(Books2A.title, "C Plus");
    strcpy(Books2A.author, "LuckyVan");
    strcpy(Books2A.subject, "C");
    Books2A.book_id = 666888;
    //Books2B 胪陈
    strcpy(Books2B.title, "C++ Plus");
    strcpy(Books2B.author, "LuckyVan");
    strcpy(Books2B.subject, "C++");
    Books2B.book_id = 666999;
    // 输出 Book1 信息
    printf("Book 1 title : %s\n", Books2A.title);
    printf("Book 1 author : %s\n", Books2A.author);
    printf("Book 1 subject : %s\n", Books2A.subject);
    printf("Book 1 book_id : %d\n", Books2A.book_id);
    // 输出 Book2 信息
    printf("Book 2 title : %s\n", Books2B.title);
    printf("Book 2 author : %s\n", Books2B.author);
    printf("Book 2 subject : %s\n", Books2B.subject);
    printf("Book 2 book_id : %d\n", Books2B.book_id);
    printf("\n\n\n");
    //结构作为函数参数
    printBook(Books2A);
    printBook(Books2B);
}
void printBook(struct Books2 book) {
    printf("Book  title : %s\n", book.title);
    printf("Book  author : %s\n", book.author);
    printf("Book  subject : %s\n", book.subject);
    printf("Book  book_id : %d\n", book.book_id);
}
int main(int argc, const char * argv[]) {
//    test1();
//    test2();
    test3();
//    Test *t = [[Test alloc]init];
//    NSLog(@"t:%@",t);
    return 0;
}

输出:

Book 1 title : C Plus
Book 1 author : LuckyVan
Book 1 subject : C
Book 1 book_id : 666888
Book 2 title : C++ Plus
Book 2 author : LuckyVan
Book 2 subject : C++
Book 2 book_id : 666999
Book  title : C Plus
Book  author : LuckyVan
Book  subject : C
Book  book_id : 666888
Book  title : C++ Plus
Book  author : LuckyVan
Book  subject : C++
Book  book_id : 666999
Program ended with exit code: 0

指向结构的指针

您能够界说指向结构的指针,办法与界说指向其他类型变量的指针相似,如下所示:

struct Books *struct_pointer;

现在,您能够在上述界说的指针变量中存储结构变量的地址。为了查找结构变量的地址,请把 & 运算符放在结构称号的前面,如下所示:

struct_pointer = &Book1;

为了运用指向该结构的指针拜访结构的成员,您有必要运用 -> 运算符,如下所示:

struct_pointer->title;

比方:

//指向结构体的指针「结构体变量」
struct hp_objc_class{
    size_t isa;
};
typedef struct hp_objc_class *HPClass;
struct HP_Person_IMPL{
    HPClass class;
    int count;
//    ...
};
//界说指向结构的指针
void printBookZZ(struct Books2 *books2);
void test4(void){
      //拜访 Books2 结构成员
    struct Books2 Books2A;//声明 Books2A 类型为 Books2
    struct Books2 Books2B;//声明 Books2B 类型为 Books2
    //Books2A 胪陈 ,将 CPlus copy 到 title 中
    strcpy(Books2A.title, "C Plus");
    strcpy(Books2A.author, "Nuha Ali");
    strcpy(Books2A.subject, "C");
    Books2A.book_id = 666888;
    //Books2B 胪陈
    strcpy(Books2B.title, "C++ Plus");
    strcpy(Books2B.author, "LuckyVan");
    strcpy(Books2B.subject, "C++");
    Books2B.book_id = 666999;
     //通过内存地址传递信息,为了查找结构变量的地址,请把 & 运算符放在结构称号的前面
     printBookZZ(&Books2A);
     printBookZZ(&Books2B);
}
/**
 * 为了运用指向该结构的指针拜访结构的成员,您有必要运用 -> 运算符,如下所示:
 * @param book
 */
void printBookZZ(struct Books2 *book) {
    printf("Book -> title : %s\n", book->title);
    printf("Book -> author : %s\n", book->author);
    printf("Book -> subject : %s\n", book->subject);
    printf("Book -> book_id : %d\n", book->book_id);
}
int main(int argc, const char * argv[]) {
//    test1();
//    test2();
//    test3();
//    Test *t = [[Test alloc]init];
//    NSLog(@"t:%@",t);
    test4();
    return 0;
}

位域

有些信息在存储时,并不需求占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只要 0 和 1 两种状况,用 1 位二进位即可。
为了节省存储空间,并使处理简便,C 言语又供给了一种数据结构,称为”位域”或”位段”。

所谓”位域”是把一个字节中的二进位划分为几个不同的区域,并阐明每个区域的位数。

  • 每个域有一个域名,答应在程序中按域名进行操作。
  • 这样就能够把几个不同的目标用一个字节的二进制位域来表明。

典型的实例:

  • 用 1 位二进位存放一个开关量时,只要 0 和 1 两种状况。
  • 读取外部文件格局——能够读取非规范的文件格局。

位域界说:

struct 位域结构称号{
  位域列表
}; 

位域列表的办法为:

类型阐明符 位域名:位域长度

例如:

//位域结构体
struct status1{
    int a;
    int b;
    int c;
};
struct status2{
    int a:1;
    int b:1;
    int c:1;
};
void test5(void){
    struct status1 s;
    struct status2 s2;
    printf("status:%lu\n",sizeof(s));
    printf("status2:%lu\n",sizeof(s2));
}
int main(int argc, const char * argv[]) {
//    test1();
//    test2();
//    test3();
//    Test *t = [[Test alloc]init];
//    NSLog(@"t:%@",t);
//    test4();
    test5();
    return 0;
}
struct bean {
  int a:8;
  int b:4;
  int c:4;
}data;

阐明 data 为 bean类型的 变量,共占 2个字节。其中位域 a 占 8 位,位域 b 占 4 位,位域 c 占 4 位。「1个字节8个方位:0000 0000」

留意:

  • 一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也能够有意使某位域从下一单元开端。例如:
struct bean{
  unsigned a:4;
  unsigned  :4;//空域
  unsigned b:4;//从下一个单元开端存放
  unsigned c:4;
} 

在这个位域界说中共占用 2 个字节,a 占榜首字节的 4 位,后 4 位填 0 表明不运用,b 从第二字节开端,占用 4 位,c 占用 4 位。

  • 由于位域不答应跨两个字节,因而位域的长度不能大于一个字节的长度,也便是说不能超过8位二进位。假如最大长度大于计算机的整数字长,一些编译器或许会答应域的内存堆叠,别的一些编译器或许会把大于一个域的部分存储在下一个字中。
  • 位域能够是无名位域,这时它只用来作填充或调整方位。无名的位域是不能运用的。例如:
struct k{
 int a:1;
 int  :2;    /* 该 2 位不能运用 */
 int b:3;
 int c:2;
};

从以上剖析能够看出,位域在本质上便是一种结构类型,不过其成员是按二进位分配的。

位域的运用

位域的运用和结构成员的运用相同,其一般办法为:

位域变量名.位域名

位域变量名->位域名

位域答应用各种格局输出。

比方:

void main(){
       //位域
     struct bs {
         unsigned int a:1;//占 位段a 1 位
         unsigned b:6;//占 位段b 3 位
         unsigned c:7;//占 位段c 4 位
     } bit, *pbit;
     // 给位域赋值(应留意赋值不能超过该位域的答应范围)
     bit.a = 1; //以二进制 1 表明 1 bit位
     bit.b = 50;//以二进制 110010 表明 6 bit位
     bit.c = 100;//以二进制 1100100 标志 7 bit位
     printf("%d,%d,%d\n",bit.a,bit.b,bit.c);    // 以整型量格局输出三个域的内容
     pbit=&bit;     //把位域变量 bit 的地址送给指针变量 pbit
     pbit->a=0;     //用指针办法给位域 a 从头赋值,赋为 0
     pbit->b&=3;     //运用了复合的位运算符 "&=",相当于:pbit->b=pbit->b&3,位域 b 华夏有值为 50,与 3 作按位与运算的成果为 2(110010&011=010,十进制值为 2)
     pbit->c|=1;     //运用了复合位运算符"|=",相当于:pbit->c=pbit->c|1,其成果为 (1100100 | 0000001)= 1100101 = 101
     printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c);     //用指针办法输出了这三个域的值
} 

输出:

1,50,100
0,2,101 

2. 共用体

共用体 是一种特殊的数据类型,答应您在相同的内存方位存储不同的数据类型。您能够界说一个带有多成员的共用体,可是任何时分只能有一个成员带有值。共用体供给了一种运用相同的内存方位的有用办法。

界说共同体

为了界说共用体,您有必要运用 union 句子,办法与界说结构相似。union 句子界说了一个新的数据类型,带有多个成员。union 句子的格局如下:

union [union tag]
{
member definition;
member definition;
...
member definition;
}[one or more union variables]; 

union tag 是可选的,每个 member definition 是规范的变量界说,比方 int i; 或许 float f;
或许其他有用的变量界说。在共用体界说的结尾,最终一个分号之前,您能够指定一个或多个共用体变量,这是可选的。下面界说一个名为 Data 的共用体类型,有三个成员 i、f 和 str:

union Data
{
int i;
float f;
char str[20];
}

现在,Data 类型的变量能够存储一个整数、一个浮点数,或许一个字符串。这意味着一个变量(相同的内存方位)能够存储多个多种类型的数据。
您能够根据需求在一个共用体内运用任何内置的或许用户自界说的数据类型。

共用体占用的内存应足够存储共用体中最大的成员。
例如,在上面的实例中,Data 将占用 20 个字节的内存空间,由于在各个成员中,字符串所占用的空间是最大的。
下面的实例将显现上面的共用体占用的总内存大小:

union Data {
    int i;
    float f;
    char str[20];
};
void main(){
    union Data data;
    printf("Memory size occupied by data: %d\n", sizeof(data));
}

输出:

Memory size occupied by data: 20

拜访共同体成员

为了拜访共用体的成员,咱们运用成员拜访运算符(.) 。成员拜访运算符是共用体变量称号和咱们要拜访的共用体成员之间的一个句号。您能够运用 union 关键字来界说共用体类型的变量。下面的实例演示了共用体的用法:

union Data {
    int i;
    float f;
    char str[20];
};
void main() {
    //1. 拜访共同体 no
    data.i = 10;
    data.f = 1314.520;
    strcpy(data.str,"C/C++");
    printf( "data.i : %d\n", data.i);
    printf( "data.f : %f\n", data.f);
    printf( "data.str : %s\n", data.str);
    printf("\n\n\n");
    //2. 拜访共同体   yes
    data.i = 10;
    printf( "data.i : %d\n", data.i);
    data.f = 1314.520;
    printf( "data.f : %f\n", data.f);
    strcpy(data.str,"C/C++");
    printf( "data.str : %s\n", data.str);
} 

输出:

data.i : 725823299
data.f : 0.000000
data.str : C/C++
data.i : 10
data.f : 1314.520020
data.str : C/C++

在这里,咱们能够看到上面注释 1 共用体的 if 成员的值有损坏,由于最终赋给变量的值占用了内存方位,这也是 str 成员能够无缺输出的原因。咱们看注释 2 ,这次咱们在同一时刻只运用一个变量成员,所以都能无缺输出。

3. 位域

参阅 17.(位域的介绍)

4. typedef

C 言语供给了 typedef 关键字,您能够运用它来为类型取一个新的姓名。
下面的实例为单字节数字界说了一个术语 BYTE

typedef unsigned char BYTE;

在这个类型界说之后,标识符 BYTE 可作为类型 unsigned char 的缩写,例如:

BYTE  b1, b2;

依照惯例,界说时会大写字母,以便提醒用户类型称号是一个象征性的缩写,但您也能够运用小写字母,如下:

typedef unsigned char byte;

您也能够运用 typedef 来为用户自界说的数据类型取一个新的姓名。例如,您能够对结构体运用 typedef 来界说一个新的数据类型姓名,然后运用这个新的数据类型来直接界说结构变量,如下:

typedef struct Books {
    char title[50];
    char author[50];
    char subject[50];
    int book_id;
} Book;
#define TRUE  1
#define FALSE  0
 void main(){
     Book book;
     strcpy( book.title, "C 教程");
     strcpy( book.author, "Runoob");
     strcpy( book.subject, "编程言语");
     book.book_id = 12345;
     printf( "书标题 : %s\n", book.title);
     printf( "书作者 : %s\n", book.author);
     printf( "书类目 : %s\n", book.subject);
     printf( "书 ID : %d\n", book.book_id);
     printf( "TRUE 的值: %d\n", TRUE);
     printf( "FALSE 的值: %d\n", FALSE);
 }

输出:

书标题 : C 教程
书作者 : Runoob
书类目 : 编程言语
书 ID : 12345
TRUE 的值: 1
FALSE 的值: 0

typedef vs define

define 是 C 指令,用于为各种数据类型界说别号,与 typedef 相似,可是它们有以下几点不同:

  • typedef 仅限于为类型界说符号称号, #define 不只能够为类型界说别号,也能为数值界说别号,比方您能够界说 1 为 ONE。
  • typedef 是由编译器执行解说的, #define 句子是由预编译器进行处理的。

比方能够参阅上面是 #define 运用。

三、C 言语中心语法|输入&输出、文件读写

1. 输入 & 输出

当咱们说到输入时,这意味着要向程序填充一些数据。输入能够是以文件的办法或从命令行中进行。C 言语供给了一系列内置的函数来读取给定的输入,并根据需求填充到程序中。

当咱们说到输出时,这意味着要在屏幕上、打印机上或恣意文件中显现一些数据。C 言语供给了一系列内置的函数来输出数据到计算机屏幕上和保存数据到文本文件或二进制文件中。

规范输出

C 言语把一切的设备都当作文件。所以设备(比方显现器)被处理的办法与文件相同。以下三个文件会在程序执行时自动翻开,以便拜访键盘和屏幕。

规范文件 文件指针 设备
规范输入 stdin 键盘
规范输出 stdout 屏幕
规范过错 stderr 您的屏幕

文件指针是拜访文件的办法,本节将解说怎么从屏幕读取值以及怎么把成果输出到屏幕上。

C 言语中的 I/O (输入/输出) 一般运用 printf()scanf() 两个函数。

scanf() 函数用于从规范输入(键盘)读取并格局化, printf() 函数发送格局化输出到规范输出(屏幕)。

比方:

void main(){
      float f;
    printf("Enter a float number: \n");
    // %f 匹配浮点型数据
    scanf("%f",&f);
    printf("Value = %f", f);
} 

输出:

Enter a float number:
12.3
Value = 12.300000 

getchar()&putchar() 函数

int getchar(void) 函数从屏幕读取下一个可用的字符,并把它回来为一个整数。这个函数在同一个时刻内只会读取一个单一的字符。您能够在循环内运用这个办法,以便从屏幕上读取多个字符。

int putchar(int c) 函数把字符输出到屏幕上,并回来相同的字符。这个函数在同一个时刻内只会输出一个单一的字符。您能够在循环内运用这个办法,以便在屏幕上输出多个字符。

void main(){
    int c;
    printf( "\nEnter a value :");
    //函数从屏幕读取下一个可用的字符,并把它回来为一个整数。这个函数在同一个时刻内只会读取一个单一的字符。您能够在循环内运用这个办法,以便从屏幕上读取多个字符。
    c = getchar( );
    printf( "\nYou entered: ");
    //读取榜首个字符
    putchar( c );
} 

输出:

Enter a value :abcdef
You entered: a 

gets() & puts() 函数

char *gets(char *s) 函数从 stdin 读取一行到 s 所指向的缓冲区,直到一个中止符或 EOF。

int puts(const char *s) 函数把字符串 s 和一个尾随的换行符写入到 stdout

void main(){
    char str[100];
    printf( "\nEnter a value :");
    //读取一行
    gets( str );
    printf( "\nYou entered: ");
    puts( str );
}

输出:

Enter a value :大家好,才是真的好!
You entered: 大家好,才是真的好!

2. 文件读写

上一节咱们解说了 C 言语处理的规范输入和输出设备。本章咱们将介绍 C 程序员怎么创立、翻开、封闭文本文件或二进制文件。

一个文件,不管它是文本文件还是二进制文件,都是代表了一系列的字节。C 言语不只供给了拜访顶层的函数,也供给了底层(OS)调用来处理存储设备上的文件。本章将解说文件办理的重要调用。

翻开文件

您能够运用 fopen( ) 函数来创立一个新的文件或许翻开一个已有的文件,这个调用会初始化类型 FILE 的一个目标,类型 FILE 包括了一切用来控制流的必要的信息。下面是这个函数调用的原型:

FILE *fopen( const char * filename, const char * mode );

在这里,filename 是字符串,用来命名文件,拜访方式 mode 的值能够是下列值中的一个:

方式 描绘
r 翻开一个已有的文本文件,答应读取文件。
w 翻开一个文本文件,答应写入文件。假如文件不存在,则会创立一个新文件。在这里,您的程序会从文件的最初写入内容。假如文件存在,则该会被截断为零长度,从头写入。
a 翻开一个文本文件,以追加方式写入文件。假如文件不存在,则会创立一个新文件。在这里,您的程序会在已有的文件内容中追加内容。
r+ 翻开一个文本文件,答应读写文件。
w+ 翻开一个文本文件,答应读写文件。假如文件已存在,则文件会被截断为零长度,假如文件不存在,则会创立一个新文件。
a+ 翻开一个文本文件,答应读写文件。假如文件不存在,则会创立一个新文件。读取会从文件的最初开端,写入则只能是追加方式。

假如处理的是二进制文件,则需求运用下面的拜访方式来替代上面的拜访方式:

"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"

封闭文件

为了封闭文件,请运用 fclose( ) 函数。函数的原型如下:

 int fclose( FILE *fp );

假如成功封闭文件,fclose( ) 函数回来零,假如封闭文件时产生过错,函数回来 EOF。这个函数实际上,会清空缓冲区中的数据,封闭文件,并开释用于该文件的一切内存。EOF 是一个界说在头文件 stdio.h 中的常量。

C 规范库供给了各种函数来按字符或许以固定长度字符串的办法读写文件。

写入文件

下面是把字符串写入到流中的最简略的函数:

int fputc(int c,FILE *fp);

函数 fputc() 把参数 c 的字符值写入到 fp 所指向的输出流中。假如写入成功,它会回来写入的字符,假如产生过错,则会回来 EOF。您能够运用下面的函数来把一个以 null 结尾的字符串写入到流中:

int fputs( const char *s, FILE *fp );

函数 fputs() 把字符串 s 写入到 fp 所指向的输出流中。假如写入成功,它会回来一个非负值,假如产生过错,则会回来 EOF。您也能够运用 int fprintf(FILE *fp,const char *format, …) 函数来写把一个字符串写入到文件中。测验下面的实例:

void main(){
      //界说一个空指针文件
    FILE *fp = NULL;
    //翻开文件,翻开一个文本文件,答应读写文件。
    // 假如文件不存在,则会创立一个新文件。
    // 读取会从文件的最初开端,写入则只能是追加方式。
    fp = fopen("/Users/devyk/Data/ClionProjects/NDK_Sample/README.md","a+");
    fprintf(fp, " fprintf 我是增加进来的1\n");
    fprintf(fp, "fprintf 我是增加进来的2\n");
    fputs("fputs 我是增加进来的1\n", fp);
    fputs("fputs 我是增加进来的2\n", fp);
    fclose(fp);
} 

读取文件

下面是从文件读取单个字符的最简略的函数:

int fgetc( FILE * fp );

fgetc() 函数从 fp 所指向的输入文件中读取一个字符。回来值是读取的字符,假如产生过错则回来 EOF。下面的函数答应您从流中读取一个字符串:

char *fgets( char *buf, int n, FILE *fp );

函数 fgets() 从 fp 所指向的输入流中读取 n – 1 个字符。它会把读取的字符串复制到缓冲区 buf,并在最终追加一个 null 字符来中止字符串。

假如这个函数在读取最终一个字符之前就遇到一个换行符 ‘\n’ 或文件的结尾 EOF,则只会回来读取到的字符,包括换行符。您也能够运用 **int fscanf(FILE fp, const char format, …) 函数来从文件中读取字符串,可是在遇到榜首个空格和换行符时,它会中止读取。

比方:

void main(){
    FILE *fp = NULL;
    //读取文件
    char buff[255];
    fp = fopen("/Users/devyk/Data/ClionProjects/NDK_Sample/README.md","r");
    fscanf(fp,"%s",buff);
    printf("1: %s\n", buff);
    fgets(buff, 255, (FILE*)fp);
    printf("2: %s\n", buff);
    fgets(buff, 255, (FILE*)fp);
    printf("3: %s\n", buff );
    fclose(fp);
}

专题系列文章

温习C言语中心常识

  • 01-温习C言语中心常识|综述
  • 02-温习C言语中心常识|基本语法、数据类型、变量、常量、存储类、基本句子(判断句子、循环句子、go to句子)和运算
  • 03-温习C言语中心常识|函数、作用域规则、数组、枚举、字符与字符串、指针
  • 04-温习C言语中心常识|结构体、共用体、位域、输入&输出、文件读写
  • 05-温习C言语中心常识|预处理、头文件、强制类型转换、过错处理、递归、内存办理